using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace FingerPoint.Android.Core
{
    public delegate void OnHandMetaHandle(HandMeta handMeta);

    public class Provider : MonoBehaviour
    {
        public enum HandMetaState
        {
            WaitData,
            Found
        }

        private static Provider instance;

        public static Provider Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = FindObjectOfType<Provider>();
                    if (instance == null)
                    {
                        var obj = new GameObject("Provider");
                        instance = obj.AddComponent<Provider>();
                        DontDestroyOnLoad(obj);
                    }
                }
                return instance;
            }
        }

        public event OnHandMetaHandle OnHandMetaFound;
        public event OnHandMetaHandle OnHandMetaProcess;
        public event OnHandMetaHandle OnHandMetaLost;
        private string sourceData;
        private HandMeta handMeta;

        public HandMetaState handMetaState = HandMetaState.WaitData;

        private float beatHeartTimer;

        private void Awake()
        {
            Screen.sleepTimeout = SleepTimeout.NeverSleep;
            JavaTool.Init();
            if (instance == null)
            {
                instance = this;
                DontDestroyOnLoad(gameObject);
            }
            if (instance != this)
            {
                Destroy(gameObject);
            }
        }

        public string SourceData()
        {
            return sourceData;
        }

        // Update is called once per frame

        void Update()
        {
            OnDataHandle();
            OnBeatHeart();
        }

        private void OnDataHandle()
        {
            sourceData = JavaTool.CallJavaMethod<string>("OnUpdate");

            switch (handMetaState)
            {
                case HandMetaState.WaitData:

                    if (string.IsNullOrEmpty(sourceData))
                    {
                        return;
                    }
                    else
                    {
                        handMeta = JsonUtility.FromJson<HandMeta>(sourceData);

                        if (handMeta.qnull == 1)
                        {
                            // Debug.Log("0  pull data fraquency to high, wait for a while ");
                            break;
                        }
                        else if (handMeta.hvisible == 0)
                        {
                            // Debug.Log("0  hvisible ==0  ,wait hand ");
                            break;
                        }
                        handMeta.cursorY = Screen.height - handMeta.cursorY;
                        OnHandMetaFound?.Invoke(handMeta);
                        OnHandMetaProcess?.Invoke(handMeta);
                        handMetaState = HandMetaState.Found;
                        // Debug.Log("0  Hand Found ");
                    }
                    break;
                case HandMetaState.Found:

                    if (string.IsNullOrEmpty(sourceData))
                    {
                        OnHandMetaLost?.Invoke(handMeta);
                        handMetaState = HandMetaState.WaitData;
                        // Debug.Log("1 sourceData is null , Hand Lost");
                        break;
                    }
                    else
                    {
                        handMeta = JsonUtility.FromJson<HandMeta>(sourceData);

                        if (handMeta.qnull == 1)
                        {
                            // pull data fraquency to high, wait for a while
                            break;
                        }
                        else if (handMeta.hvisible == 0)
                        {
                            OnHandMetaLost?.Invoke(handMeta);
                            handMetaState = HandMetaState.WaitData;
                            // Debug.Log("1 hvisible ==0 , Hand Lost  ");
                            // hand not visible
                            break;
                        }
                        handMeta.cursorY = Screen.height - handMeta.cursorY;
                        OnHandMetaProcess?.Invoke(handMeta);
                        // Debug.Log("1 Hand Process  " + handMeta.millisecondOffsets);
                    }
                    break;
            }
        }

        private void OnBeatHeart()
        {
            if (Time.realtimeSinceStartup - beatHeartTimer > 0)
            {
                beatHeartTimer = Time.realtimeSinceStartup + 2;
                JavaTool.CallJavaMethod("OnBeatHeart");
            }
        }
    }

    #region 结构

    public enum GestureEnum
    {
        nullGesture,
        pinch,
        pinching,
        loose,
        longpinching,
        dragloose
    }

    public class HandMeta
    {
        /**
         * 0: null
         * 1: has hand
         */
        public int qnull;

        /**
         * 0: false
         * 1: true
         */
        public int hvisible;

        /**
         * current time in milliseconds
         */
        public long unixTimeInMills;

        /**
         * hand identity, for multiple hands
         */
        public int hid;

        /**
         * hand label:
         * 0: left hand
         * 1: right hand
         */
        public int hlabel;

        /**
         * cursor location on screen
         * cursorX: x
         */
        public int cursorX;

        /**
         * cursor location on screen
         * cursorX: y
         */
        public int cursorY;

        /**
         * 0: null
         * 1: pinch
         * 2: pinching
         * 3: loose
         * 4: longpinching
         * 5: dragloose
         */
        public GestureEnum gesture;

        public int millisecondOffsets;
    }

    #endregion

    #region Java 工具

    //Java 工具
    public class JavaTool
    {
        private static AndroidJavaObject currentActivity;

        private static bool isInit = false;

        public static void Init()
        {
            var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            try
            {
                currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
                isInit = true;
                CallJavaMethod("StartProcess");
            }
#if UNITY_EDITOR
            catch
            {
                Debug.Log("编辑器调试模式,可以直接使用鼠标触发UI事件 ");
            }
#else
            catch (System.Exception e)
            {
                Debug.Log(e);
            }
#endif
        }

        public static void CallJavaMethodStatic(string methodName)
        {
            if (isInit == false)
                return;
            currentActivity.CallStatic(methodName);
        }

        public static void CallJavaMethod(string methodName)
        {
            if (isInit == false)
                return;
            currentActivity.Call(methodName);
        }

        public static T CallJavaMethodStatic<T>(string methodName)
        {
            if (isInit == false)
                return default(T);
            return currentActivity.CallStatic<T>(methodName);
        }

        public static T CallJavaMethod<T>(string methodName)
        {
            if (isInit == false)
                return default(T);
            return currentActivity.Call<T>(methodName);
        }
    }
    #endregion
}
